package com.dixon.worddayday.config;

import com.dixon.worddayday.config.BusinessException;
import com.dixon.worddayday.response.BaseRes;
import com.dixon.worddayday.response.ResponseCode;
import com.google.gson.Gson;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

@RestControllerAdvice
public class GlobalExceptionHandler {
    Logger logger = LogManager.getLogger(getClass().getName());

    @ExceptionHandler(value = Exception.class)
    public BaseRes defaultErrorHandler(HttpServletRequest request, Exception e) throws Exception {
        BaseRes res = new BaseRes();
        if (e instanceof HttpRequestMethodNotSupportedException) {
            res.setCode(ResponseCode.HTTP_METHOD_NOT_SUPPORT.getCode());
            res.setDesc(ResponseCode.HTTP_METHOD_NOT_SUPPORT.getDesc());
        } else if (e instanceof HttpMediaTypeNotSupportedException) {
            res.setCode(ResponseCode.HTTP_MEDIA_TYPE_NOT_SUPPORTED_EXCEPTION.getCode());
            res.setDesc(ResponseCode.HTTP_MEDIA_TYPE_NOT_SUPPORTED_EXCEPTION.getDesc());
        } else if(e instanceof BusinessException) {
            BusinessException be = (BusinessException) e;
            res.setCode(be.getCode());
            res.setDesc(be.getMessage());
        } else if(e instanceof IllegalArgumentException) {
            res.setCode(ResponseCode.BUSINESS_EXCEPTION.getCode());
            res.setDesc(e.getMessage());
        }

        else {
            res.setCode(ResponseCode.SYSTEM_EXCEPTION.getCode());
            res.setDesc(ResponseCode.SYSTEM_EXCEPTION.getDesc());
        }
        logger.info(request.getRequestURI() + " response: " + new Gson().toJson(res));

        if(!(e instanceof BusinessException))
            logger.error("", e);
        return res;
    }

    @ExceptionHandler(value = MaxUploadSizeExceededException.class)
    public BaseRes uploadExceptionHandler(HttpServletRequest request, MaxUploadSizeExceededException e) throws Exception {
        BaseRes res = new BaseRes();
        res.setCode(ResponseCode.UPLOAD_BEYOND_MAX.getCode());
        res.setDesc(ResponseCode.UPLOAD_BEYOND_MAX.getDesc());
        logger.info(request.getRequestURI() + " response: " + new Gson().toJson(res));
        logger.error("", e);
        return res;
    }

    /**
     * 处理请求单个参数不满足校验规则的异常信息
     *
     * @param request
     * @param exception
     * @return
     * @throws Exception
     */
    @ExceptionHandler(value = {BindException.class, MethodArgumentNotValidException.class})
    public BaseRes bindExceptionExceptionHandler(HttpServletRequest request, Exception exception) {
        logger.info(exception.getMessage());
        BaseRes res = new BaseRes();
        res.setCode(ResponseCode.DATA_INVALID.getCode());
        res.setDesc(ResponseCode.DATA_INVALID.getDesc());
        BindingResult result = null;
        if(exception instanceof BindException){
            result = ((BindException) exception).getBindingResult();
        }else{
            result = ((MethodArgumentNotValidException) exception).getBindingResult();
        }
        if (result != null) {
            List<ObjectError> list = result.getAllErrors();
            if (!CollectionUtils.isEmpty(list)) {
                StringBuilder errMsg = new StringBuilder();
                for (ObjectError error : list) {
                    if (errMsg.length() > 0)
                        errMsg.append(",");
                    errMsg.append(error.getDefaultMessage());
                }
                res.setDesc(errMsg.toString());
            }
        }
        return res;
    }
}
